package alignment

import (
	"errors"
	"fmt"
	"reflect"
	"unsafe"
)

type Test1 struct {
	A int32 //4
	B int64 //8
	C uint8 //1
}

type Test2 struct {
	C uint8 //1
	A int32 //4
	B int64 //8
}

type Test3 struct {
	A int32 //4
	C uint8 //1
	B int64 //8
	D []int
	E interface{}
}

func OutLine() {
	t1 := Test1{}
	t2 := Test2{}

	fmt.Printf("%v,%p,%v,%v\n", t1.A, &t1.A, unsafe.Sizeof(t1.A), unsafe.Offsetof(t1.A))
	fmt.Printf("%v,%p,%v,%v\n", t1.B, &t1.B, unsafe.Sizeof(t1.B), unsafe.Offsetof(t1.B))
	fmt.Printf("%v,%p,%v,%v\n", t1.C, &t1.C, unsafe.Sizeof(t1.C), unsafe.Offsetof(t1.C))

	fmt.Printf("%v,%p,%v\n", t1, &t1, unsafe.Sizeof(t1))

	fmt.Printf("%v,%p,%v,%v\n", t2.C, &t2.C, unsafe.Sizeof(t2.C), unsafe.Offsetof(t2.C))
	fmt.Printf("%v,%p,%v,%v\n", t2.A, &t2.A, unsafe.Sizeof(t2.A), unsafe.Offsetof(t2.A))
	fmt.Printf("%v,%p,%v,%v\n", t2.B, &t2.B, unsafe.Sizeof(t2.B), unsafe.Offsetof(t2.B))

	fmt.Printf("%v,%p,%v\n", t2, &t2, unsafe.Sizeof(t2))
}
func OutLine1() {
	t1 := Test1{}
	t2 := Test2{}
	t3 := Test3{}

	fmt.Printf("size:%v,offset:%v,align:%v\n", unsafe.Sizeof(t1.A), unsafe.Offsetof(t1.A), unsafe.Alignof(t1.A))
	fmt.Printf("size:%v,offset:%v,align:%v\n", unsafe.Sizeof(t1.B), unsafe.Offsetof(t1.B), unsafe.Alignof(t1.B))
	fmt.Printf("size:%v,offset:%v,align:%v\n", unsafe.Sizeof(t1.C), unsafe.Offsetof(t1.C), unsafe.Alignof(t1.C))

	fmt.Printf("%v,%v\n", unsafe.Sizeof(t1), unsafe.Alignof(t1))

	fmt.Printf("size:%v,offset:%v,align:%v\n", unsafe.Sizeof(t2.C), unsafe.Offsetof(t2.C), unsafe.Alignof(t2.A))
	fmt.Printf("size:%v,offset:%v,align:%v\n", unsafe.Sizeof(t2.A), unsafe.Offsetof(t2.A), unsafe.Alignof(t2.B))
	fmt.Printf("size:%v,offset:%v,align:%v\n", unsafe.Sizeof(t2.B), unsafe.Offsetof(t2.B), unsafe.Alignof(t2.C))

	fmt.Printf("%v,%v\n", unsafe.Sizeof(t2), unsafe.Alignof(t2))

	fmt.Printf("size:%v,offset:%v,align:%v\n", unsafe.Sizeof(t3.A), unsafe.Offsetof(t3.A), unsafe.Alignof(t3.B))
	fmt.Printf("size:%v,offset:%v,align:%v\n", unsafe.Sizeof(t3.C), unsafe.Offsetof(t3.C), unsafe.Alignof(t3.A))
	fmt.Printf("size:%v,offset:%v,align:%v\n", unsafe.Sizeof(t3.B), unsafe.Offsetof(t3.B), unsafe.Alignof(t3.C))
	fmt.Printf("size:%v,offset:%v,align:%v\n", unsafe.Sizeof(t3.D), unsafe.Offsetof(t3.D), unsafe.Alignof(t3.D))
	fmt.Printf("size:%v,offset:%v,align:%v\n", unsafe.Sizeof(t3.E), unsafe.Offsetof(t3.E), unsafe.Alignof(t3.E))

	fmt.Printf("%v,%v\n", unsafe.Sizeof(t3), unsafe.Alignof(t3))

	fmt.Println("t:", unsafe.Sizeof(struct {
		C int32
		A int32
		D int64
		B int8
	}{}))
}

//CPU 读取内存是一块一块读取的,64位一般按8位读取
//减少内存碎片，以及方便CPU读取。
//unsafe.Sizeof() 返回一个类型实际使用大小
//unsafe.Offsetof() 返回一个字段在结构体中的偏移量
//unsafe.Alignof() 返回一个类型的对齐系数
//规则1：结构体中除第一个元素偏移值为0，其后每个元素的偏移值为自己Size的整数倍数，补齐对齐值
//规则2：结构体所有元素对齐后，整个结构体需要对齐，对齐规则为默认对齐长度或元素中类型长度最大的整数倍数，补齐对齐值
func StructSize(T interface{}) (enumSize []int64, structSize int64, err error) {
	t := reflect.TypeOf(T)
	if t.Kind() != reflect.Struct {
		err = errors.New("invalid arg need struct")
		return
	}
	for i := 0; i < t.NumField(); i++ {
		argType := t.Field(i)
		fmt.Println(argType.Offset)
		enumSize = append(enumSize, int64(argType.Type.Size()))
	}
	last := t.Field(t.NumField() - 1)
	structSize = int64(last.Offset) + int64(last.Type.Size())
	if structSize%8 != 0 {
		structSize += 8 - structSize%8
	}
	//structSize = int64(obj.Len())
	return
}
